# 拉普拉斯算子是图像二阶空间导数的二维各向同性测度。
# 拉普拉斯算子可以突出图像中强度发生快速变化的区域，
# 因此常用在边缘检测任务当中。
# 在进行Laplacian操作之前通常需要先用高斯平滑滤波器对图像进行平滑处理，
# 以降低Laplacian操作对于噪声的敏感性。
# 该操作通常是输入一张灰度图，经过处理之后输出一张灰度图。

# 图像对应的拉普拉斯算子L(x,y)可以通过卷积核进行计算，由于图片是采用离散的像素值
# 集合进行表示的，因此我们可以寻找一个近似于拉普拉斯算子的二阶倒是离散卷积核

"""
Log运算计算图片在空间上的二阶导数，这意味着图片中某个区域的强度是固定值的时候，
其LOG变化的响应值为0,而在图片的强度发生变化的区域，在较暗的一侧的LoG的响应值
是正数，而在较亮的一侧,LoG的响应值则为负数
"""

import torch
import torch.nn.functional as F
import numpy as np

from torch.autograd import Variable
from math import exp
from PIL import Image
from torchvision.utils import save_image, make_grid

# 最后矩阵的元素归一化
def minmaxscaler(data):
    min_d = torch.min(data)
    max_d = torch.max(data)
    return (data - min_d) / (max_d - min_d)

# LoG变换
def LoG(img, window, window_size, mode="RGB"):
    img1_array = np.array(img, dtype=np.float32) # Image -> array
    img1_tensor = torch.from_numpy(img1_array)
    # 处理不同通道的数据
    if mode == 'L':
        # unsqueeze()用于增加维度
        img1_tensor = img1_tensor.unsqueeze(0).unsqueeze(0)
    else: # RGB or RGBA
        # permute可以对任意高维矩阵进行转置.但只有 tensor.permute() 这个调用方式
        img1_tensor = img1_tensor.permute(2, 0, 1) # h.w.c -> c.h.w
        img1_tensor = img1_tensor.unsqueeze(0) # c.h.w -> n.c.h.w
    channel = img1_tensor.size()[1]
    window = Variable(window.expand(channel, 1, window_size, window_size).contiguous())
    output = F.conv2d(img1_tensor, window, padding=window_size//2, groups=channel)
    output = minmaxscaler(output)
    if (channel == 4):
        save_image(output, 'output.png', normalize=False)
    else:
        save_image(output, 'output.png', normalize=False)
    return output
#近似卷积核
window  = torch.Tensor([[[0,1,1,2,2,2,1,1,0],
                        [1,2,4,5,5,5,4,2,1],
                        [1,4,5,3,0,3,5,4,1],
                        [2,5,3,-12,-24,-12,3,5,2],
                        [2,5,0,-24,-40,-24,0,5,2],
                        [2,5,3,-12,-24,-12,3,5,2],
                        [1,4,5,3,0,3,4,4,1],
                        [1,2,4,5,5,5,4,2,1],
                        [0,1,1,2,2,2,1,1,0]]])
window_size = 9
img = Image.open("../resource/Lena.jpg")
img = img.convert('L')
LoG(img,window,window_size,img.mode)



